using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input.Touch;
using System.Threading;
using System.IO.IsolatedStorage;
using System.IO;
using ebookreader.Resources;

namespace ebookreader
{
    public class ScrollBar
    {
        Rectangle rectangle;
        public int total_elements;
        int viewed_elements;
        public int firstelement;
        Color bar_color, pick_color;

        Texture2D white;
        public ScrollBar(int viewed_elements, Rectangle rectangle, Texture2D white)
            :this(viewed_elements, rectangle, white, Color.White*(51f / 255f),Color.White*(153f / 255f))
        {            
        }

        public ScrollBar(int viewed_elements, Rectangle rectangle, Texture2D white, Color bar_color, Color pick_color)
        {
            this.viewed_elements = viewed_elements;
            this.rectangle = rectangle;
            this.white = white;
            this.bar_color = bar_color;
            this.pick_color = pick_color;
            
            //last_position = rectangle.Top;
        }

        
        public void Draw(SpriteBatch sprite_batch, float dt){
            sprite_batch.Draw(white, rectangle, bar_color);
            DrawPicker(sprite_batch,dt);
        }

        private float last_position = 0;
        public void DrawPicker(SpriteBatch sprite_batch, float dt){
            if (total_elements == 0) return;
            var picker_height = Math.Max(5,Math.Min(rectangle.Height, rectangle.Height * ((float)viewed_elements / total_elements)));
            var position = Math.Min((1.0f / total_elements) * firstelement * rectangle.Height, rectangle.Height-picker_height);
            last_position = MathHelper.Lerp(last_position, position, dt*5);
            sprite_batch.Draw(white, new Rectangle(rectangle.X, rectangle.Y+(int)last_position, rectangle.Width, (int)picker_height), pick_color);
        }
    }

    public class BookSelection : Menu
    {
        #region Fields
        static readonly int LIST_MARGIN = 25;
        int MARGIN = 5;
        GraphicsDeviceManager graphics;

        State currentState;

        SpriteFont font_small_titles;
        //SpriteBatch sprite_batch;
        Vector2 position = new Vector2(LIST_MARGIN, LIST_MARGIN);

        //Texture2D ui_title_box, ui_date_box;
        //Texture2D ui_title_ordering_none, ui_title_ordering_up, ui_title_ordering_down;
        //Texture2D ui_date_ordering_none, ui_date_ordering_up, ui_date_ordering_down;
        int title_box_heigth = 130;


        TextureButton orderbytitlebutton;
        TextureButton orderbydatebutton;

        //List<Book> currentState.booksList;
        List<BoxedLabelScrollableButton> books_buttons = new List<BoxedLabelScrollableButton>();
        #endregion


        public BookSelection(Game game, SpriteFont font)
            : base(game)
        {
            //this.font = font;
            //this.font = game.Content.Load<SpriteFont>("Fonts/lista");


            //UpdateOrder = (int)screenorder.reader;
            //draworder = (int)screenOrder.Reader;

            //game.Exiting += new EventHandler<EventArgs>(SaveState);
        }

        public override void Initialize()
        {

            //Game.Components.Add(new InputManager(Game));

            currentState = Game.Services.GetService(typeof(State)) as State;
            graphics = Game.Services.GetService(typeof(GraphicsDeviceManager)) as GraphicsDeviceManager;
            sprite_batch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;
            //input_manager = Game.Services.GetService(typeof(IInputManager)) as IInputManager;
            input_manager.OnTap += new InputManager.Tap(OnTap);
            input_manager.OnPress += new InputManager.Tap(OnHold);

            input_manager.onBackButtonPressed += new InputManager.Back(() => { ScreenManager.SelectMainMenu(Game); });

            base.Initialize();
        }

        string prev_free_url = "";
        int [] bookOrder;
        Texture2D back, background, background_er, menu_button, ui_title_box, main_book, az, pref;
        SpriteFont font_title, font_author, font_button;
        SoundEffect slide;
        int LIST_SPACING = 75;
        ScrollBar scrollbar;
        protected override void LoadContent()
        {
            back = Game.Content.Load<Texture2D>("Definitivo/back");
            background = Game.Content.Load<Texture2D>("Definitivo/background");
            background_er = Game.Content.Load<Texture2D>("todo/logo2");
            menu_button = Game.Content.Load<Texture2D>("Definitivo/menu_button");
            ui_title_box = Game.Content.Load<Texture2D>("Definitivo/title_box");
            main_book = Game.Content.Load<Texture2D>("Definitivo/book");
            az = Game.Content.Load<Texture2D>("Definitivo/az_order");
            pref = Game.Content.Load<Texture2D>("Definitivo/pref_order");

            font_title = Game.Content.Load<SpriteFont>("Fonts/menu_sx");
            font_small_titles = font_author = Game.Content.Load<SpriteFont>("Fonts/menu_piccolo");
            font_button = Game.Content.Load<SpriteFont>("Fonts/menu");
            var white = Game.Content.Load<Texture2D>("todo/white");

            scrollbar = new ScrollBar(2, new Rectangle(573, 46, 12, 387), white);
            scrollbar.total_elements = currentState.booksList.Count;


            slide = Game.Content.Load<SoundEffect>("Sound/slide_down");


            MARGIN = 465 - ui_title_box.Width / 2;
            //ui_title_box = Game.Content.Load<Texture2D>("Textures/UI/BookList/title_box");
            //ui_title_ordering_none = Game.Content.Load<Texture2D>("Textures/UI/BookList/title_order_none");
            //ui_title_ordering_up = Game.Content.Load<Texture2D>("Textures/UI/BookList/title_order_up");
            //ui_title_ordering_down = Game.Content.Load<Texture2D>("Textures/UI/BookList/title_order_down");

            //ui_date_box = Game.Content.Load<Texture2D>("Textures/UI/BookList/date_box");
            //ui_date_ordering_none = Game.Content.Load<Texture2D>("Textures/UI/BookList/date_order_none");
            //ui_date_ordering_up = Game.Content.Load<Texture2D>("Textures/UI/BookList/date_order_up");
            //ui_date_ordering_down = Game.Content.Load<Texture2D>("Textures/UI/BookList/date_order_down");

            //sprite_batch = Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;

            #region ADD DEFAULT BOOKS
            if (currentState.booksList.Count == 0)
            {
                string[] preloaded_books = new string[] { "1000", "8800" };
                DownloadBook.loadDownloadStatus();
                for (int i = 0; i < preloaded_books.Length; i++)
                {
                    var book = DownloadBook.booksList.FirstOrDefault(b => b.id.Equals(preloaded_books[i]));
                    var index = DownloadBook.booksList.IndexOf(book);
                    if (book == null)
                    {
                        Thread.Sleep(100);
                        i--;
                        continue;
                    }
                    IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
                    IsolatedStorageFileStream stream = store.OpenFile(book.id + ".txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
                    StreamWriter sw = new StreamWriter(stream);
                    var s = new StreamReader(TitleContainer.OpenStream(Game.Content.RootDirectory + "/Books/" + book.id + ".txt"));
                    var str = s.ReadToEnd();
                    s.Close();
                    sw.Write(str);
                    sw.Close();
                    stream.Close();
                    currentState.booksList.Add(new Book()
                    {
                        filename = book.id + ".txt",
                        currentWord = 0,
                        title = book.title,
                        authors = book.authors,
                        lang = book.lang
                    });
                    DownloadBook.downloadStatusList[index] = 1;
                }
            }
            #endregion

            bookOrder = new int[currentState.booksList.Count];
            for (int i=0; i<currentState.booksList.Count; i++)
            {
                bookOrder[i]=i;
                books_buttons.Add(null);
            }




            var addCustomBook = new TextureButton(sprite_batch, Game.Content.Load<Texture2D>("Definitivo/add"), new Vector2(730, 410), Color.White, currentState.options);
            addCustomBook.OnPress += new Press((me) =>
            {
                if (!Guide.IsVisible)
                    Guide.BeginShowKeyboardInput(
                       PlayerIndex.One,
                       "Insert the txt book's URL",
                       "",
                       prev_free_url,
                       new AsyncCallback(OnEndShowKeyboardInput),
                       null
                    );
            });
            entries.Add(addCustomBook);



            var readButton = new BoxedLabelButton(sprite_batch, menu_button, new Vector2(94, 82), font_button, Lang.MM_Read, Color.White, false, currentState.options);
            readButton.OnPress += new Press((_) =>
                {
                    if (selected_book == null)
                        return;
                  selected_book.lastRead = DateTime.Now;
                  ScreenManager.StartBookReader(Game, selected_book); 
                });
            entries.Add(readButton);
            //int i = 0;
            //titleOrderButtonPressed(null);


            orderbytitlebutton = new TextureButton(sprite_batch, az, new Vector2(225, 39), currentState.options);
            orderbytitlebutton.OnPress += new Press(titleOrderButtonPressed);
            entries.Add(orderbytitlebutton);

            orderbydatebutton = new TextureButton(sprite_batch, pref, new Vector2(292, 39), currentState.options);
            orderbydatebutton.OnPress += new Press(dateOrderButtonPressed);
            entries.Add(orderbydatebutton);

            var back_button = new TextureButton(sprite_batch, back, Vector2.Zero, currentState.options);
            back_button.OnPress += new Press(
                (me) => { ScreenManager.SelectMainMenu(Game); }
                );
            entries.Add(back_button);

            //graphics.SetLandscapeRightOrientation();


            base.LoadContent();
        }

        protected override void Dispose(bool disposing)
        {           
            Game.Services.RemoveService(typeof(IInputManager));

            //graphics.SetLandscapeRightOrientation();

            base.Dispose(disposing);
        }


        int firstIndex, prev_first_index;
        Book selected_book;
        int selected_book_index;
        float toComponentstart = 0;
        public override void Update(GameTime gameTime)
        {
            toComponentstart += (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (!EbookReader.state.hints[2] && toComponentstart > 1)
            {
                Game.Components.Add(new LargeMessagePopup(Game, Lang.Tip, Lang.TIP3));
                EbookReader.state.hints[2] = true;
            }

            if (prev_first_index != firstIndex && currentState.options.audio)
                slide.Play();
            prev_first_index = firstIndex;
            if (!dragging)
            {
                offsetPosition.Y += forceY;
                if (Math.Abs(forceY) >= 1f)
                    forceY = MathHelper.Lerp(forceY, 0.0f,
                        (float)gameTime.ElapsedGameTime.TotalSeconds * (float)Math.Max(60 / Math.Abs(forceY), 4f));
                else
                    forceY = 0.0f;


                var fixPosition = 10000.0f;
                firstIndex = 0;
                int i=0;
                for (; i < books_buttons.Count; i++ )
                {
                    var m = books_buttons[bookOrder[i]];
                    if (m == null)
                    {
                        addBookButtonList(currentState.booksList[bookOrder[i]], bookOrder[i], i);
                        m = books_buttons[bookOrder[i]];
                    }
                    m.splitLabel();
                    if (bookOrder[i] > 0 && bookOrder[i] > books_buttons.Count)
                        continue;
                    if (Math.Abs(fixPosition) > Math.Abs((m.box_position.Y + offsetPosition.Y) - LIST_MARGIN - ui_title_box.Height - LIST_SPACING))
                    {
                        fixPosition = m.box_position.Y + offsetPosition.Y - LIST_MARGIN - ui_title_box.Height - LIST_SPACING;
                        firstIndex = i;
                    }
                    m.active = true;
                    if (m.box_position.Y + offsetPosition.Y < LIST_MARGIN - 10 ||
                        m.box_position.Y + offsetPosition.Y > GraphicsDevice.Viewport.Height - title_box_heigth)
                        m.active = false;
                    //i++;
                }
                scrollbar.firstelement = firstIndex;

                if (fixPosition != 0.0f)
                    offsetPosition.Y =
                        MathHelper.Lerp(offsetPosition.Y, offsetPosition.Y-fixPosition, 
                        (float)gameTime.ElapsedGameTime.TotalSeconds * 5);

                if (bookOrder.Length> 0 && firstIndex <= bookOrder.Length)
                {
                    selected_book_index = bookOrder[firstIndex];
                    selected_book =currentState.booksList[selected_book_index];
                    labels.Clear();
                    positions.Clear();
                    splitLabel(selected_book.title, font_title, new Rectangle(39, 170, 287, 140));
                }

            }

            //if (GamePad.GetState(PlayerIndex.One).IsButtonDown(Buttons.Back))
            //    ScreenManager.SelectMainMenu(Game);

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            
            sprite_batch.Begin();
            sprite_batch.Draw(background, GraphicsDevice.Viewport.Bounds, Color.White);
            sprite_batch.Draw(background_er, new Vector2(644,23), Color.White);

            //sprite_batch.Draw(menu_button, new Vector2(94, 82), Color.White);
            //sprite_batch.DrawString(font, Lang.MM_DownM, new Vector2(94 + 20, 82 + menu_button.Height / 2 - font.MeasureString(Lang.MM_DownM).Y / 2), Color.White);

            for (int i = Math.Max(0, firstIndex - 3); i < Math.Min(firstIndex + 3, bookOrder.Length); i++)
            {
                var m = books_buttons[bookOrder[i]];
                if (m == null)
                {
                    addBookButtonList(currentState.booksList[bookOrder[i]], bookOrder[i], i);
                    m = books_buttons[bookOrder[i]];
                }
                var scale = MathHelper.Lerp(0.7f, 1.2f, 1 - (Math.Abs(240 - m.rectangle.Center.Y - m.scrollOffset.Y)) / 240.0f);
                var dest = new Rectangle(
                    (int)(m.rectangle.Center.X - main_book.Width / 2 * scale),
                    (int)(m.rectangle.Center.Y + m.scrollOffset.Y - main_book.Height / 2 * scale),
                    (int)(main_book.Width * scale), (int)(main_book.Height * scale));
                sprite_batch.Draw(main_book, dest, Color.White * (float)Math.Pow(scale * 0.833f, 2));               
                //sprite_batch.DrawString(font,""+scale,  new Vector2(dest.X+200, dest.Y), Color.White);
            }



            for (int i = 0; i < labels.Count; i++)
            {
                sprite_batch.DrawString(font_title, labels[i], positions[i], Color.White);
            }

            if (selected_book != null)
            {
                sprite_batch.DrawString(font_author, selected_book.authors, new Vector2(320 - font_author.MeasureString(selected_book.authors).X, 317), Color.White);
                //var lang_str = Lang.Language + " [" + selected_book.lang + "]";
                if(selected_book.lastRead.Year>2000)
                sprite_batch.DrawString(font_author, ""+selected_book.lastRead, new Vector2(320 - font_author.MeasureString(""+selected_book.lastRead).X, 345), Color.White);
            }

            scrollbar.Draw(sprite_batch, (float)gameTime.ElapsedGameTime.TotalSeconds);
            sprite_batch.End();

            base.Draw(gameTime);
        }

        
        private void SaveNewBook(List<Book> books, Book book)
        {
            books.Add(book);
            //SaveBookList(books);
            currentState.SaveState();
        }

        #region ordering books list
        bool descending_title = true;
        void titleOrderButtonPressed(MenuEntry m_)
        {
            for (int j = 0; j < bookOrder.Length; j++)
                bookOrder[j] = j;
           Array.Sort<int>(bookOrder, new Comparison<int>(
               (i1, i2) =>
               {
                   return String.Compare(currentState.booksList[i1].title, currentState.booksList[i2].title);
               }));

           //orderbydatebutton.texture = ui_date_ordering_none;
           if (descending_title)
           {
               //orderbytitlebutton.texture = ui_title_ordering_down;
               Array.Reverse(bookOrder);
           }
           else
           {
               //orderbytitlebutton.texture = ui_title_ordering_up;
           }

           for (int i = 0; i < bookOrder.Length; i++)
           {
               books_buttons[bookOrder[i]].box_position =  new Vector2(MARGIN, LIST_MARGIN + i * (ui_title_box.Height + LIST_SPACING));
           }

           descending_title = !descending_title;
        }


        bool descending_date = true;
        void dateOrderButtonPressed(MenuEntry m_)
        {
            for (int j = 0; j < bookOrder.Length; j++)
                bookOrder[j] = j;
            Array.Sort<int>(bookOrder, new Comparison<int>( 
                (i1, i2) => {
                    var b = DateTime.Compare(currentState.booksList[i1].lastRead, currentState.booksList[i2].lastRead);
                    return b; 
            }));

            //orderbytitlebutton.texture = ui_title_ordering_none;
            if (descending_date)
            {
                //orderbydatebutton.texture = ui_date_ordering_down;
                Array.Reverse(bookOrder);
            }
            else
            {
                //orderbydatebutton.texture = ui_date_ordering_up;
            }


            for (int i = 0; i < bookOrder.Length; i++)
            {
                books_buttons[bookOrder[i]].box_position =  new Vector2(MARGIN, LIST_MARGIN + i * (ui_title_box.Height + LIST_SPACING));
            }
            descending_date = !descending_date;
        }




        private void addBookButtonList(Book book, int index, int index_position)
        {
            var nb = new BoxedLabelScrollableButton(sprite_batch, ui_title_box, new Vector2(MARGIN, LIST_MARGIN + index_position * (ui_title_box.Height + LIST_SPACING)),
                   font_small_titles, new Vector2(0, 0), book.title, Color.White, Color.Black, currentState.options);
            nb.OnPress += new Press((MenuEntry m) =>
            {
                book.lastRead = DateTime.Now;
                //SaveBookList(books);
                ScreenManager.StartBookReader(Game, book);
            });
            nb.OnHolded += new Hold((me) =>
            {
                Game.Components.Add(new AlertPopup(Game, Lang.DeleteBook+"\n"+book.title, () =>
                    {
                        currentState.booksList.Remove(book);
                        var ind = books_buttons.IndexOf((BoxedLabelScrollableButton)me);
                        int ind2 = 0;
                        for (int i = 0; i < bookOrder.Length; i++)
                            if (bookOrder[i] == ind) { ind2 = i; break; }
                        bookOrder = bookOrder.Take(ind).Concat(bookOrder.Skip(ind + 1)).ToArray();
                        for (int i = 0; i < bookOrder.Length; i++)
                        {
                            books_buttons[bookOrder[i]].box_position = new Vector2(MARGIN, LIST_MARGIN + i * (ui_title_box.Height + LIST_SPACING));
                            if (bookOrder[i] >= ind) bookOrder[i] = bookOrder[i] - 1;
                        }
                        books_buttons.Remove((BoxedLabelScrollableButton)me);
                        entries.Remove(me);

                    }));
            });
            
            books_buttons[index] = nb; ;
            entries.Add(nb);
        }
        #endregion


        List<Vector2> positions = new List<Vector2>(), shadow_positions = new List<Vector2>();
        List<string> labels = new List<string>();

        void splitLabel(string label, SpriteFont font, Rectangle _box)
        {
            var ls = label.Split(new char[] { ' ' });
            var c_l = "";
            for (int i = 0; i < ls.Length; i++)
            {
                if (labels.Count > 2)
                {
                    labels[2] += "...";
                    break;
                };
                var l = " " + ls[i];
                while (font.MeasureString(l).X >= _box.Width)
                {
                    l = l.Substring(0, l.Length / 2) + "..";
                }
                if (font.MeasureString(c_l + l).X < _box.Width)
                    c_l += l;
                else
                {
                    labels.Add(c_l);
                    c_l = "";
                    i--;
                }
            }
            if (!c_l.Equals("")) labels.Add(c_l);

            for (int i = 0; i < labels.Count; i++)
            {
                var l = labels[i];
                var pos = new Vector2(_box.X + (_box.Width - font.MeasureString(l).X),
                    _box.Y + _box.Height / 2 + ((i - labels.Count / 2) * (font.MeasureString("I").Y)) - font.MeasureString("I").Y / 2);
                positions.Add(pos);
                shadow_positions.Add(pos + Vector2.One * 2.0f);

            }

        }


        private void OnEndShowKeyboardInput(IAsyncResult result)
        {
            var text = Guide.EndShowKeyboardInput(result);
            
            if (text != null)
            {
                prev_free_url = text;
                downloadCustomBook(text);
            }
            //textArea.text = Guide.EndShowKeyboardInput(result);
            //if (textArea.text == null)
            //    textArea.text = Strings.WriteHere;
        }

         public void downloadCustomBook(string url)
        {
            if (EbookReader.isTrial && EbookReader.state.numDownloaded>=2)
            {
                Game.Components.Add(new MessagePopup(Game, Lang.Trial, Lang.NoDownload));
                //if (currentState.options.audio)
                //    fail.Play();
                return;
            }
            //booksInDownload++;
            //var current_selected_book = booksList[index];
            //downloadStatusList[index] = 3;
            //Game.Components.Add(new MessagePopup(Game, Lang.Downloading, url));
            Utils.Project.getCustomEBook(url, (s) =>
            {
                if (s.StartsWith("<!DOCTYPE"))
                {
                    //booksInDownload--;
                    //downloadStatusList[index] = 2;
                    //if (currentState.options.audio)
                    //    fail.Play();
                    return;
                }
                if (!Guide.IsVisible)
                    Guide.BeginShowKeyboardInput(
                       PlayerIndex.One,
                       "Insert book's title",
                       "",
                       "",
                       new AsyncCallback((result) =>
                       {
                            var text = Guide.EndShowKeyboardInput(result);
                            if (text != null)
                            {
                                EbookReader.state.numDownloaded++;
                                IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
                                IsolatedStorageFileStream stream = store.OpenFile(text + ".txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
                                StreamWriter sw = new StreamWriter(stream);
                                sw.Write(s);
                                sw.Close();
                                stream.Close();

                                currentState.booksList.Add(new Book()
                                {
                                    filename = text+".txt",
                                    currentWord = 0,
                                    title = text,
                                    authors = "",
                                    lang = "",
                                    lastRead = System.DateTime.Now
                                });
                                currentState.SaveState();
                                books_buttons.Add(null);
                                var bo = bookOrder.ToList();
                                bo.Add(bookOrder.Length);
                                bookOrder = bo.ToArray();
                                addBookButtonList(currentState.booksList.Last(), bookOrder[bookOrder.Length - 1], bookOrder.Length-1);
                                dateOrderButtonPressed(null);
                            }
                       }),
                       null
                    );

                //booksInDownload--;

                //downloadStatusList[index] = 1;
                //if (currentState.options.audio)
                //    success.Play();
            },
                () =>
                {
                    //booksInDownload--;
                    Game.Components.Add(new MessagePopup(Game, "Error downloading", url));
                    //downloadStatusList[index] = 2;
                    //if (currentState.options.audio)
                    //    fail.Play();
                }

                );
        }

    }
}
